package com.david.fastmsg.handler;

import com.david.fastmsg.Constant.Constant;
import com.david.fastmsg.bean.Message;
import com.david.fastmsg.enums.MessageType;
import com.david.fastmsg.modal.Chat;
import com.david.fastmsg.modal.Room;
import com.david.fastmsg.modal.Users;
import com.david.fastmsg.repository.ChatRepository;
import com.david.fastmsg.repository.RoomRepository;
import com.david.fastmsg.repository.UserRepository;
import com.david.fastmsg.utils.JsonUtils;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @author qzw
 * @date 2021/9/2
 */
@Sharable
@Component
public class WebsocketMessageHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    private static final Logger LOGGER = LoggerFactory.getLogger(WebsocketMessageHandler.class);

    /**
     * 存储用户对应的通道
     */
    Map<String, ChannelHandlerContext> channelHandlerContextMap = new ConcurrentHashMap<>();

    /**
     * 存放通道到用户关联
     */
    Map<String, String> channelUserMap = new ConcurrentHashMap<>();

    /**
     * 存储当前链接上的通道
     */
    private List<ChannelHandlerContext> channelHandlerContextList = new CopyOnWriteArrayList<>();

    @Autowired
    private ChatRepository chatRepository;

    @Autowired
    private RoomRepository roomRepository;

    @Autowired
    private UserRepository userRepository;

    /**
     * 断开事件
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        String sendUserId = channelUserMap.get(ctx.channel().id().toString());
        channelHandlerContextMap.remove(sendUserId);
        // 依次通知所有的用户
        for (ChannelHandlerContext handlerContext : channelHandlerContextMap.values()) {
            // Message message = new Message("服务端", null, UUID.randomUUID().toString(), "用户" + s + "已经离线了",2);
            handlerContext.writeAndFlush(new TextWebSocketFrame("用户" + sendUserId + "已经离线了"));
        }
        channelHandlerContextList.remove(ctx);
        channelUserMap.remove(ctx.channel().id().toString());
        LOGGER.info("链接断开：{}", ctx.channel().remoteAddress());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        String s = channelUserMap.get(ctx.channel().id().toString());
        channelHandlerContextMap.remove(s);
        // 依次通知所有的用户
        for (ChannelHandlerContext handlerContext : channelHandlerContextMap.values()) {
            // Message message = new Message("服务端", null, UUID.randomUUID().toString(), "用户" + s + "已经离线了",2);
            handlerContext.writeAndFlush(new TextWebSocketFrame("用户" + s + "已经被迫离线了"));
        }
        channelHandlerContextList.remove(ctx);
        channelUserMap.remove(ctx.channel().id().toString());
        LOGGER.info("链接异常：{}", ctx.channel().remoteAddress());
    }

    /**
     * 链接事件
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        channelHandlerContextList.add(ctx);
        LOGGER.info("有新的链接创建：" + ctx.channel().remoteAddress() + ",链接总数量： " + channelHandlerContextList.size());
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
        LOGGER.info("前端发来消息：" + msg.text());
        Message message = JsonUtils.stringToClassOfT(msg.text(), Message.class);
        // 处理登录的消息
        if (message.getType() == 1) {
            setMap(ctx, message);
            message.setSend(Constant.SERVER);
            ctx.writeAndFlush(new TextWebSocketFrame(JsonUtils.objectToJsonString(message)));
            return;
        }
        // 处理聊天的消息
        // 处理好友邀请
        if (message.getType() == 2 || message.getType() == 3) {
            // 获取到需要转发的客户端
            String receiveUserId = message.getReceiveUserId();
            String receive = message.getReceive();
            String send = message.getSend();
            String sendUserId = message.getSendUserId();
            ChannelHandlerContext receiveCtx = channelHandlerContextMap.get(receiveUserId);
            // 从缓存的存储用户对应的通道 map中获取
            if (receiveCtx != null) {
               // LOGGER.info("send不为空");
                Users user = userRepository.findByUserId(sendUserId);
                Message messageSend = new Message(UUID.randomUUID().toString(), send, sendUserId, receive, receiveUserId,
                        message.getInfo(), message.getFileType(), message.getType(), user.getPicSmall());
                receiveCtx.writeAndFlush(new TextWebSocketFrame(JsonUtils.objectToJsonString(messageSend)));
            } else {
                ChannelHandlerContext sendCtx = channelHandlerContextMap.get(message.getSendUserId());
                Message messageSend = new Message(UUID.randomUUID().toString(), null, null,
                        receive, receiveUserId, Constant.USER_NOT_ONLINE, message.getFileType(),
                        MessageType.OFFLINE.getType(), message.getPic());
                sendCtx.writeAndFlush(new TextWebSocketFrame(JsonUtils.objectToJsonString(messageSend)));
            }
        }
        // 创建群聊后，在每一个群聊用户页面创建一个群聊窗口
        if (message.getType() == 4) {
            String receiveUserId = message.getReceiveUserId();
            String receive = message.getReceive();
            String send = message.getSend();
            String sendUserId = message.getSendUserId();
            Chat chat = chatRepository.findByRoomId(receiveUserId);
            List<String> userList = JsonUtils.stringToList(chat.getChatList());
            for (String userId: userList) {
                ChannelHandlerContext receiveCtx = channelHandlerContextMap.get(userId);
                if (receiveCtx != null) {
                    Room room = roomRepository.findByRoomId(receiveUserId);
                    Message messageSend = new Message(UUID.randomUUID().toString(), send, sendUserId, receive, receiveUserId,
                            message.getInfo(), message.getFileType(), message.getType(), room.getRoomPicSmall());
                    receiveCtx.writeAndFlush(new TextWebSocketFrame(JsonUtils.objectToJsonString(messageSend)));
                }
            }
        }
        // 群聊消息开始，正事开始通信
        if (message.getType() == 5) {
            String receiveUserId = message.getReceiveUserId();
            String receive = message.getReceive();
            String send = message.getSend();
            String sendUserId = message.getSendUserId();
            Chat chat = chatRepository.findByRoomId(receiveUserId);
            List<String> chatList = JsonUtils.stringToList(chat.getChatList());
            for (String chatId: chatList) {
                if (chatId.equals(sendUserId)) {
                    continue;
                }
                ChannelHandlerContext receiveCtx = channelHandlerContextMap.get(chatId);
                if (receiveCtx != null) {
                    Users user = userRepository.findByUserId(sendUserId);
                    Message messageSend = new Message(UUID.randomUUID().toString(), user.getUserName(),
                            user.getUserId(), receive, receiveUserId, message.getInfo(), message.getFileType(),
                            message.getType(), user.getPicSmall());
                    receiveCtx.writeAndFlush(new TextWebSocketFrame(JsonUtils.objectToJsonString(messageSend)));
                }
            }
        }
    }

    /**
     * 设置连接映射
     *
     * @param channelHandlerContext
     * @param message
     */
    private void setMap(ChannelHandlerContext channelHandlerContext, Message message) {
        LOGGER.info("setMap,[sendUserId]:" + message.getSendUserId()
                + ",[send]:" + message.getSend()
                + ",[receiveUserId]:" + message.getReceiveUserId()
                + ",[receive]:" + message.getReceive()
                + ",[type]:" + message.getType()
                + ",[id]" + channelHandlerContext.channel().id().toString());
        channelHandlerContextMap.put(message.getSendUserId(), channelHandlerContext);
        channelUserMap.put(channelHandlerContext.channel().id().toString(), message.getSendUserId());
    }

}
